package com.sky.service.impl;

import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ShoppingCartMapper;
import com.sky.mapper.UserAddressBookMapper;
import com.sky.service.OrderServer;
import com.sky.vo.OrderSubmitVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class OrderServerImpl implements OrderServer {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserAddressBookMapper userAddressBookMapper;

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    /**
*     1.走业务判断
*     2.封装订单数据
*     3.得到订单ID，交给订单明细
*     4.玩儿订单明细
*     5.清空购物车
*     6.封装返回结果
     * @param ordersSubmitDTO
     * @return
     */
    @Override
    public OrderSubmitVO orderServer(OrdersSubmitDTO ordersSubmitDTO) {
        //1.走业务判断
        //1.1前端传没传id
        Long addressBookId = ordersSubmitDTO.getAddressBookId();
        if (addressBookId == null) {
            throw new AddressBookBusinessException(MessageConstant.PARAMS_MISSED);
        }

        //1.2如果我传了这个id 但是数据库误删了呢
        AddressBook addressBook=userAddressBookMapper.findById(addressBookId);
        if (addressBook == null) {
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        //TODO 地址距离判断 -day09 文档说明
        //1.3购物车的判断
        Long userId= BaseContext.getCurrentId();
        ShoppingCart condition = ShoppingCart.builder().userId(userId).build();
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.findShoppingCartByCondition(condition);
        if (shoppingCartList==null||shoppingCartList.size()==0) {
            throw new OrderBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        //2.封装订单数据 保存 类一和类二 的属性值要相互对应！
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        //封装 订单状态 订单号 用户ID 支付状态
        orders.setStatus(Orders.PENDING_PAYMENT);
        //订单号: 能重复么？ 不能重复，建议趋势递增 好构建索引 好检索提高效率 暂时用时间戳 项目二 分布式架构！ 订单生成策略
        //UUID 订单号会参与检索 经常参加检索 要不要添加索引（查询速度变快，影响索引构建的效率） UUID没顺序B+Tree
        //RandomString 又没有顺序
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setUserId(userId);
        orders.setPayStatus(Orders.UN_PAID);
        //封装 收货地址信息
        orders.setPhone(addressBook.getPhone());
        orders.setAddress(addressBook.getDetail());
        orders.setConsignee(addressBook.getConsignee());
        orders.setOrderTime(LocalDateTime.now());
        //用户名暂时不设置
        orderMapper.save(orders);

        //3.封装订单明细
        //3.1 获取订单ID
        Long ordersId = orders.getId();
        //3.2 封装订单
        List<Object> orderDetailList = shoppingCartList.stream()
            .map(shoppingCart -> {
            //将购物车的数据都封装给orderDetail
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(shoppingCart, orderDetail);
            orderDetail.setOrderId(ordersId);
            return orderDetail;
        }).collect(Collectors.toList());
        //3.3批量插入
        //insert into 表 (id,name) values (?,?),(?,?),(?,?)
        orderDetailMapper.batchInsert(orderDetailList);

        //4.清空购物车
        shoppingCartMapper.delete(userId);
        //5.封装数据
        OrderSubmitVO vo = OrderSubmitVO.builder()
                .id(ordersId)
                .orderTime(orders.getOrderTime())
                .orderAmount(orders.getAmount())
                .orderNumber(orders.getNumber())
                .build();
        return vo;
    }
}
